<template>
  <el-form
    ref="form"
    v-if="model"
    v-bind="$attrs"
    :model="model"
    :rules="rules"
    :validate-on-rule-change="false"
  >
    <template v-for="(item, index) in options" :key="index">
      <el-form-item
        v-if="!item.children || !item.children.length"
        :label="item.label"
        :prop="item.prop"
      >
        <component
          v-if="item.type !== 'upload' && item.type !== 'editor'"
          v-bind="item.attrs"
          :is="`el-${item.type}`"
          v-model="model[item.prop!]"
        ></component>
        <!-- 文件上传组件 -->
        <el-upload
          v-if="item.type === 'upload'"
          v-bind="item.uploadAttrs"
          :on-preview="onPreview"
          :on-remove="onRemove"
          :on-success="onSuccess"
          :on-error="onError"
          :on-progress="onProgress"
          :on-change="onChange"
          :on-exceed="onExceed"
          :before-upload="beforeUpload"
          :before-remove="beforeRemove"
          :http-request="httpRequest"
        >
          <div>
            <slot name="uploadArea"></slot>
            <slot name="uploadTip"></slot>
          </div>
        </el-upload>
        <!-- 富文本 -->
        <div v-if="item.type === 'editor'" style="border: 1px solid #ccc">
          <Toolbar
            style="border-bottom: 1px solid #ccc"
            :editor="editorRef"
            :defaultConfig="toolbarConfig"
            mode="default"
          />
          <Editor
            style="height: 500px; overflow-y: hidden"
            v-model="valueHtml"
            :defaultConfig="editorConfig"
            mode="default"
            @onCreated="handleCreated"
            @onBlur="hanldeBlur"
          />
        </div>
      </el-form-item>
      <!-- 有children -->
      <el-form-item
        v-if="item.children && item.children.length != 0"
        :label="item.label"
        :prop="item.prop"
      >
        <component
          v-bind="item.attrs"
          :is="`el-${item.type}`"
          v-model="model[item.prop!]"
        >
          <component
            v-for="(item2, index2) in item.children"
            :key="index2"
            :label="item2.label"
            :prop="item2.prop"
            :value="item2.value"
            :is="`el-${item2.type}`"
          ></component>
        </component>
      </el-form-item>
    </template>
    <!-- 提交按钮 -->
    <el-form-item>
      <slot name="action" :form="form" :model="model"></slot>
    </el-form-item>
  </el-form>
</template>

<script lang="ts" setup>
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
import {
  PropType,
  ref,
  onMounted,
  watch,
  onBeforeUnmount,
  shallowRef,
} from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { FormInstance, FormOptions } from "./type/type";
import cloneDeep from "lodash/cloneDeep";

let emits = defineEmits([
  "on-preview",
  "on-remove",
  "on-success",
  "on-error",
  "on-progress",
  "on-change",
  "on-exceed",
  "before-upload",
  "before-remove",
]);
let props = defineProps({
  options: {
    type: Array as PropType<FormOptions[]>,
    required: true,
  },
  // 用户自定义上传方法
  httpRequest: {
    type: Function,
  },
});
// data
let model = ref<any>(null);
let rules = ref<any>(null);
let form = ref<FormInstance | null>(null);
// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef();
// 内容 HTML
const valueHtml = ref("");
const toolbarConfig = {};
const editorConfig = { placeholder: "请输入内容..." };
let initForm = () => {
  if (props.options && props.options.length) {
    let m: any = {};
    let r: any = {};
    props.options.map((item) => {
      m[item.prop!] = item.value; //给对应的字段名称赋对应的字段value
      r[item.prop!] = item.rules;
      if (item.type === "editor") {
        valueHtml.value = item.value;
      }
    });
    model.value = cloneDeep(m);
    rules.value = cloneDeep(r);
    console.log(model.value, rules.value);
  }
};
onMounted(() => {
  initForm();
});
// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});

watch(
  () => props.options,
  () => {
    initForm();
  }
);
// 重置表单
const resetFields = () => {
  // 重置element-plus表单
  form.value?.resetFields();
  // 重置富文本
  valueHtml.value = "";
};
// 表单验证
const validate=()=>{
  return form.value?.validate;
}
// 获取表单数据
const getFormData=()=>{
  return model.value;
}
const handleCreated = (editor) => {
  editorRef.value = editor; // 记录 editor 实例，重要！
};
const hanldeBlur = (editor: any) => {
  props.options.forEach((item) => {
    if (item.type === "editor") {
      model.value[item.prop!] = editor.getHtml();
    }
  });
};
// upload方法
let onPreview = (file: File) => {
  emits("on-preview", file);
};
let onRemove = (file: File, fileList: FileList) => {
  emits("on-remove", { file, fileList });
};
let onSuccess = (response: any, file: File, fileList: FileList) => {
  // 上传成功，给表单上传项赋值
  let uploadItem = props.options.find((item) => item.type === "upload")!;
  model.value[uploadItem.prop!] = { response, file, fileList };
  emits("on-success", { response, file, fileList });
};
let onError = (err: any, file: File, fileList: FileList) => {
  emits("on-error", { err, file, fileList });
};
let onProgress = (event: any, file: File, fileList: FileList) => {
  emits("on-progress", { event, file, fileList });
};
let onChange = (file: File, fileList: FileList) => {
  emits("on-change", { file, fileList });
};
let onExceed = (file: File, fileList: FileList) => {
  emits("on-exceed", { file, fileList });
};
let beforeUpload = (file: File) => {
  emits("before-upload", file);
};
let beforeRemove = (file: File, fileList: FileList) => {
  emits("before-remove", { file, fileList });
};

// 分发方法
defineExpose({ resetFields,validate,getFormData });
</script>
<style lang="scss" scoped></style>
